home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000
/
Ham Radio 2000.iso
/
ham2000
/
tcp_ip
/
tnos
/
tnos100s
/
nrcmd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-27
|
41KB
|
1,682 lines
/* net/rom user command processing
* Copyright 1989 by Daniel M. Frank, W9NK. Permission granted for
* non-commercial distribution only.
*/
/* Mods by G1EMM, PA0GRI and WG7J */
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <dos.h>
#include "config.h"
#include "global.h"
#include "mbuf.h"
#include "ax25.h"
#include "mailbox.h"
#include "netrom.h"
#include "nr4.h"
#include "timer.h"
#include "iface.h"
#include "pktdrvr.h"
#include "lapb.h"
#include "cmdparse.h"
#include "session.h"
#include "socket.h"
#include "commands.h"
#include "files.h"
int Nr_hidden = 1;
unsigned Nr_sorttype = 1;
char Nr4user[AXALEN];
char *Nr4states[] = {
"Disconnected",
"Conn Pending",
"Connected",
"Disc Pending",
"Listening"
} ;
char *Nr4reasons[] = {
"Normal",
"By Peer",
"Timeout",
"Reset",
"Refused"
} ;
static int dobcnodes __ARGS((int argc,char *argv[],void *p));
static int dobcpoll __ARGS((int argc,char *argv[],void *p));
static int dointerface __ARGS((int argc,char *argv[],void *p));
static int donfadd __ARGS((int argc,char *argv[],void *p));
static int donfdrop __ARGS((int argc,char *argv[],void *p));
static int donfdump __ARGS((void));
static int donfmode __ARGS((int argc,char *argv[],void *p));
static int donodefilter __ARGS((int argc,char *argv[],void *p));
static int donodetimer __ARGS((int argc,char *argv[],void *p));
static int donralias __ARGS((int argc,char *argv[],void *p));
static int donracktime __ARGS((int argc,char *argv[],void *p));
static int donrmycall __ARGS((int argc,char *argv[],void *p));
static int donrchoketime __ARGS((int argc,char *argv[],void *p));
static int donrconnect __ARGS((int argc,char *argv[],void *p));
static int donrirtt __ARGS((int argc,char *argv[],void *p));
static int donrkick __ARGS((int argc,char *argv[],void *p));
static int dorouteadd __ARGS((int argc,char *argv[],void *p));
static int doroutedrop __ARGS((int argc,char *argv[],void *p));
static int donrqlimit __ARGS((int argc,char *argv[],void *p));
static int donrreset __ARGS((int argc,char *argv[],void *p));
static int donrretries __ARGS((int argc,char *argv[],void *p));
static int donrroute __ARGS((int argc,char *argv[],void *p));
static int donrstatus __ARGS((int argc,char *argv[],void *p));
static int donrsave __ARGS((int argc,char *argv[],void *p));
static int donrload __ARGS((int argc,char *argv[],void *p));
static int donrttl __ARGS((int argc,char *argv[],void *p));
static int donruser __ARGS((int argc,char *argv[],void *p));
static int donrwindow __ARGS((int argc,char *argv[],void *p));
void doobsotick __ARGS((void));
static int doobsotimer __ARGS((int argc,char *argv[],void *p));
static int dominquality __ARGS((int argc,char *argv[],void *p));
static int donrtype __ARGS((int argc,char *argv[],void *p));
static int donrpromisc __ARGS((int argc,char *argv[],void *p));
static int donrderate __ARGS((int argc,char *argv[],void *p));
static int doroutesort __ARGS((int argc,char *argv[],void *p));
static int donrhidden __ARGS((int argc,char *argv[],void *p));
int donrneighbour __ARGS((int argc,char *argv[],void *p));
extern int donr4tdisc __ARGS((int argc,char *argv[],void *p));
extern struct nr_bind *find_best __ARGS((struct nr_bind *list,unsigned obso));
extern void nrresetlinks __ARGS((struct nrroute_tab *rp));
static struct cmds DFAR Nrcmds[] = {
"acktime", donracktime, 0, 0, NULLCHAR,
"alias", donralias, 0, 0, NULLCHAR,
"bcnodes", dobcnodes, 0, 2, "netrom bcnodes <iface>",
"bcpoll", dobcpoll, 0, 2, "netrom bcpoll <iface>",
#ifdef ALLSESSIONS
"connect", donrconnect, 1024, 2, "netrom connect <node>",
#endif
"call", donrmycall, 0, 0, NULLCHAR,
"choketime", donrchoketime, 0, 0, NULLCHAR,
"derate", donrderate, 0, 0, NULLCHAR,
"hidden", donrhidden, 0, 0, NULLCHAR,
"interface", dointerface, 0, 0, NULLCHAR,
"irtt", donrirtt, 0, 0, NULLCHAR,
"kick", donrkick, 0, 2, "netrom kick <&nrcb>",
"load", donrload, 0, 0, NULLCHAR,
"minquality", dominquality, 0, 0, NULLCHAR,
"neighbour", donrneighbour, 0, 0, NULLCHAR,
"nodefilter", donodefilter, 0, 0, NULLCHAR,
"nodetimer", donodetimer, 0, 0, NULLCHAR,
"obsotimer", doobsotimer, 0, 0, NULLCHAR,
"promiscuous", donrpromisc, 0, 0, NULLCHAR,
"qlimit", donrqlimit, 0, 0, NULLCHAR,
"route", donrroute, 0, 0, NULLCHAR,
"reset", donrreset, 0, 2, "netrom reset <&nrcb>",
"retries", donrretries, 0, 0, NULLCHAR,
"status", donrstatus, 0, 0, NULLCHAR,
"save", donrsave, 0, 0, NULLCHAR,
#ifdef ALLSESSIONS
#ifdef ALLSERV
"split", donrconnect, 1024, 2, "netrom split <node>",
#endif
#endif
"timertype", donrtype, 0, 0, NULLCHAR,
"ttl", donrttl, 0, 0, NULLCHAR,
#ifdef NR4TDISC
"tdisc", donr4tdisc, 0, 0, NULLCHAR,
#endif
"user", donruser, 0, 0, NULLCHAR,
"window", donrwindow, 0, 0, NULLCHAR,
NULLCHAR,
} ;
extern char Myalias[AXALEN]; /* the NETROM alias in 'call' form */
extern char Nralias[ALEN+1]; /* the NETROM alias in 'alias' form */
struct timer Nodetimer ; /* timer for nodes broadcasts */
struct timer Obsotimer ; /* timer for aging routes */
/* Command multiplexer */
int
donetrom(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
return subcmd(Nrcmds,argc,argv,p) ;
}
static struct cmds Routecmds[] = {
"add", dorouteadd, 0, 6,
"netrom route add <alias> <destination> <interface> <quality> <neighbor>",
"drop", doroutedrop, 0, 4,
"netrom route drop <destination> <neighbor> <interface>",
"info", dorouteinfo, 0, 0,
"",
"sort", doroutesort, 0, 1,
"",
NULLCHAR,
} ;
/* Route command multiplexer */
static int
donrroute(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
if(argc < 2) {
doroutedump() ;
return 0 ;
}
return subcmd(Routecmds,argc,argv,p) ;
}
/* Code to sort Netrom node listing
* D. Crompton 2/92
* Dump a list of known netrom routes in
* sorted order determined by sort
* flag - default = sort by alias
*/
int
doroutedump()
{
extern unsigned Nr_sorttype;
register struct nrroute_tab *rp ;
register int i,j,k, column ;
char buf[17] ;
char *cp,*temp ;
column = 1 ;
for(i = 0,j=0 ; i < NRNUMCHAINS ; i++)
for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ;j++,rp = rp->next);
if (j) {
/* Allocate maximum size */
temp = mallocw (j*17);
for(i = 0,j=0,k=0 ; i < NRNUMCHAINS ; i++)
for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
if(!Nr_hidden && *rp->alias == '#')
continue;
if (Nr_sorttype) {
strcpy(buf,rp->alias) ;
/* remove trailing spaces */
if((cp = strchr(buf,' ')) == NULLCHAR)
cp = &buf[strlen(buf)] ;
if(cp != buf) /* don't include colon for null alias */
*cp++ = ':' ;
pax25(cp,rp->call) ;
} else {
pax25(buf,rp->call);
cp=&buf[strlen(buf)];
*cp++=':';
strcpy(cp,rp->alias);
}
sprintf(&temp[k],"%-16.16s",buf);
k+=17;
j++; /* number actually shown */
}
qsort(temp,(size_t)j,17,strcmp);
for (i=0,k=0;i<j;i++,k+=17) {
tprintf("%-16s ",&temp[k]) ;
if(column++ == 4) {
if(tprintf("\n") == EOF) {
free(temp);
return 0;
}
column = 1 ;
}
}
if(column != 1)
tputc('\n') ;
free(temp);
}
return 0 ;
}
/* netrom Route Dump Sort - ALIAS or CALL first */
static
doroutesort(argc,argv,p)
int argc ;
char *argv[] ;
void *p ;
{
extern unsigned Nr_sorttype;
if(argc < 2) {
tprintf("Netrom Sort by %s\n", Nr_sorttype ? "Alias" : "Call" ) ;
return 0 ;
}
switch(argv[1][0]) {
case 'A':
case 'a':
Nr_sorttype = 1 ;
break ;
case 'C':
case 'c':
Nr_sorttype = 0 ;
break ;
default:
tprintf("usage: netrom sort [alias|call]\n") ;
return -1 ;
}
return 0 ;
}
/* Print detailed information on ALL routes (sorted) */
/* D. Crompton */
void
doallinfo()
{
extern unsigned Nr_sorttype;
register struct nrroute_tab *rp ;
register struct nr_bind *bp ;
register struct nrnbr_tab *np ;
char dest[AXALEN] ;
char neighbor[AXBUF] ;
char buf[17];
char *cp,*temp;
int i,j,k, flow_tmp;
flow_tmp=Current->flowmode;
Current->flowmode=1;
for (i=0,j=0;i<NRNUMCHAINS;i++)
for (rp=Nrroute_tab[i];rp!=NULLNRRTAB;rp= rp->next)
for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next,j++);
if (j) {
temp=mallocw (j*50);
for (i=0,k=0;i<NRNUMCHAINS;i++)
for (rp=Nrroute_tab[i];rp!=NULLNRRTAB;rp= rp->next)
for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next,k+=50) {
np = bp->via ;
if (Nr_sorttype) {
strcpy(buf,rp->alias) ;
if((cp = strchr(buf,' ')) == NULLCHAR)
cp = &buf[strlen(buf)] ;
if(cp != buf)
*cp++ = ':' ;
pax25(cp,rp->call) ;
} else {
pax25(buf,rp->call);
cp=&buf[strlen(buf)];
*cp++=':';
strcpy(cp,rp->alias);
}
sprintf(&temp[k],"%-16s %3d %3d %-8s %-9s %c\n",buf,
bp->quality,bp->obsocnt,
np->iface->name,
pax25(neighbor,np->call),
(bp->flags & NRB_PERMANENT ? 'P' :
bp->flags & NRB_RECORDED ? 'R' : 'B'));
}
qsort(temp,(size_t)j,50,strcmp);
for (i=0,k=0;i<j;i++,k+=50)
if (tprintf("%s",&temp[k])==EOF)
break;
free (temp);
Current->flowmode=flow_tmp;
}
}
/* print detailed information on an individual route
* Shows alias as well - WG7J
*/
int
dorouteinfo(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
char *cp;
register struct nrroute_tab *rp ;
register struct nrroute_tab *npp;
struct nr_bind *bp ;
struct nrnbr_tab *np ;
char dest[AXALEN] ;
char destbuf[AXBUF];
char neighbor[AXBUF] ;
char alias[AXALEN];
char buf[AXALEN];
char nb_alias[AXALEN];
int print_header=1;
int16 rhash;
if (argc == 1) {
doallinfo();
return 0;
}
putalias(alias,argv[1],0);
strupr(argv[1]); /*make sure it's upper case*/
if((rp = find_nrboth(alias,argv[1])) == NULLNRRTAB){
/*no such call or node alias*/
tputs("no such node\n\n");
return 0;
}
/*copy the real alias*/
strcpy(buf,rp->alias) ;
if((cp = strchr(buf,' ')) != NULLCHAR)
*cp = '\0';
for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next) {
np = bp->via ;
/*now we have to find the alias of the neighbour used
*so we can print that as well!
*/
rhash = nrhash(np->call);
for(npp=Nrroute_tab[rhash];npp!=NULLNRRTAB;npp=npp->next)
if(addreq(npp->call,np->call))
break;
/* found, now remove trailing spaces */
strcpy(nb_alias,npp->alias) ;
if((cp = strchr(nb_alias,' ')) != NULLCHAR)
*cp = '\0';
if(print_header) {
print_header = 0;
tputs(" Node Neighbour Port PQual Obsocnt Type\n");
tprintf("%6s:%-9s ",buf,pax25(destbuf,rp->call));
} else
tputs(" ");
tprintf("%6s:%-9s %-3s %3d %d %c\n",
nb_alias,pax25(neighbor,np->call),
np->iface->name,
bp->quality,bp->obsocnt,
bp->flags & NRB_PERMANENT ? 'P' : \
(bp->flags & NRB_RECORDED ? 'R' : 'B') );
}
tputc('\n');
return 0 ;
}
int
donrneighbour(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int i,printheader=1;
struct nrnbr_tab *np;
struct nrroute_tab *rp;
struct nr_bind *bind;
int16 rhash;
int justused;
char tmp[AXBUF];
char alias[AXALEN];
char *cp;
int quality = 0;
int obsocnt = 0;
for(i=0;i<NRNUMCHAINS;i++) /*loop through all chains of neighbours*/
for(np=Nrnbr_tab[i];np!=NULLNTAB;np=np->next) {
if(printheader) {
tputs("Routes :\n Neighbour Port PQual Obsocnt Dest\n");
printheader = 0;
}
/* has this one been used recently ? */
if((secclock() - np->lastsent) < 60)
justused = 1;
else
justused = 0;
/*now we have to find the alias of this neighbour
*so we can print that as well!
*/
rhash = nrhash(np->call);
for(rp=Nrroute_tab[rhash];rp!=NULLNRRTAB;rp=rp->next)
if(addreq(rp->call,np->call))
break;
if(rp != NULLNRRTAB) {
/* found, now remove trailing spaces */
strcpy(alias,rp->alias) ;
if((cp = strchr(alias,' ')) != NULLCHAR)
*cp = '\0';
/*find the quality for this neighbour*/
bind = find_best(rp->routes,1);
quality = bind->quality;
obsocnt = bind->obsocnt;
} else {
strcpy(alias,"##TEMP");
}
/* print it all out */
tprintf("%s %6s:%-9s %-5s %4d %1d %3d\n",
(justused) ? ">" : " ",
alias,pax25(tmp,np->call),
np->iface->name,
quality,obsocnt,np->refcnt);
}
if(!printheader)
tputc('\n');
return 0;
}
#ifdef MAILBOX
extern char Mbnrid[];
extern void setmbnrid();
#endif
/* define the netrom alias*/
static int
donralias(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
int len;
char tmp[AXBUF];
if(argc < 2) {
tprintf("%s\n",pax25(tmp,Myalias));
return 0;
}
if((setcall(Myalias,argv[1]) == -1) ||
(putalias(Nralias,argv[1],1) == -1)) {
tputs("can't set alias\n");
return 0;
}
#ifdef MAILBOX
setmbnrid();
#endif
return 0;
}
/* define the netrom call,
* this simply changes the interface linkaddress!
* but is a little easier to use...
*/
static int
donrmycall(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
int len;
char tmp[AXALEN];
if(Nr_iface == NULLIF) {
tputs("Attach netrom interface first\n") ;
return 1 ;
}
if(argc < 2) {
if (Nr_iface->hwaddr == NULLCHAR)
tputs("not set\n");
else
tprintf("%s\n",pax25(tmp,Nr_iface->hwaddr));
} else {
if( (len=strlen(argv[1])) > (AXBUF - 1)) {
tputs("too long\n");
return 1;
}
if(Nr_iface->hwaddr != NULLCHAR)
free(Nr_iface->hwaddr);
Nr_iface->hwaddr = mallocw(Nr_iface->iftype->hwalen);
(*Nr_iface->iftype->scan)(Nr_iface->hwaddr,argv[1]);
#ifdef MAILBOX
setmbnrid();
#endif
}
return 0;
}
/* make an interface available to net/rom */
/* arguments are:
* argv[0] - "interface"
* argv[1] - "iface" , the interface name
* argv[2] - "quality", the interface broadcast quality
* argv[3] - "n" or "v", to override the default (verbose)
* n = never broadcast verbose
* v = always broadcast verbose
*/
static
int
dointerface(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
register struct iface *ifp ;
int i,mtu ;
if(Nr_iface == NULLIF) {
tputs("Attach netrom interface first\n") ;
return 1 ;
}
if(argc < 3) {
i = 0;
for(ifp=Ifaces;ifp;ifp=ifp->next) {
if(ifp->flags & IS_NR_IFACE){
if(!i) {
i = 1;
tputs("Iface Qual Verbose\n");
}
tprintf("%-6s %-3d %c\n",
ifp->name,ifp->quality,
(ifp->flags & NR_VERBOSE)?'Y':'N');
}
}
return 0;
}
if((ifp = if_lookup(argv[1])) == NULLIF){
tprintf(Badinterface,argv[1]);
return 1;
}
if(ifp->type != CL_AX25){
tprintf("Interface %s is not NETROM compatible\n",argv[1]);
return 1;
}
/* activate the interface */
ifp->flags |= IS_NR_IFACE;
/* set quality */
if((ifp->quality=atoi(argv[2])) > 255) /*Maximum quality possible*/
ifp->quality = 255;
/*check to see if quality is not 0 */
if(ifp->quality == 0)
ifp->quality = 1;
/* default is none-verbose */
ifp->flags &= ~NR_VERBOSE;
if(argc > 3)
if(*argv[3] == 'v')
ifp->flags |= NR_VERBOSE;
/* Check, and set the NETROM MTU - WG7J */
if((mtu = ifp->paclen - 20) < Nr_iface->mtu)
Nr_iface->mtu = mtu;
/* Poll other nodes on this interface */
nr_bcpoll(ifp);
return 0 ;
}
/* convert a null-terminated alias name to a blank-filled, upcased */
/* version. Return -1 on failure. */
int
putalias(to,from,complain)
register char *to, *from ;
int complain ;
{
int len, i ;
if((len = strlen(from)) > ALEN) {
if(complain)
tprintf("alias too long - six characters max\n") ;
return -1 ;
}
for(i = 0 ; i < ALEN ; i++) {
if(i < len) {
if(islower(*from))
*to++ = toupper(*from++) ;
else
*to++ = *from++ ;
}
else
*to++ = ' ' ;
}
*to = '\0' ;
return 0 ;
}
/* Add a route */
static int
dorouteadd(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
char alias[AXALEN] ;
char dest[AXALEN] ;
unsigned quality ;
char neighbor[AXALEN] ;
struct iface *ifp;
int naddr ;
/* format alias (putalias prints error message if necessary) */
if(putalias(alias,argv[1],1) == -1)
return -1 ;
/* format destination callsign */
if(setcall(dest,argv[2]) == -1) {
tprintf("bad destination callsign\n") ;
return -1 ;
}
/* find interface */
if((ifp = if_lookup(argv[3])) == NULLIF) {
tprintf(Badinterface,argv[3]);
return 1;
}
/* Is it a netrom interface ? */
if(!(ifp->flags & IS_NR_IFACE)) {
tprintf(Badinterface,argv[3]) ;
return -1 ;
}
/* get and check quality value */
if((quality = atoi(argv[4])) > 255) {
tprintf("maximum route quality is 255\n") ;
return -1 ;
}
/* Change from 871225 -- no digis in net/rom table */
naddr = argc - 5 ;
if(naddr > 1) {
tprintf("Use the ax25 route command to specify digipeaters\n") ;
return -1 ;
}
/* format neighbor address string */
setcall(neighbor,argv[5]) ;
return nr_routeadd(alias,dest,ifp,quality,neighbor,1,0) ;
}
/* drop a route */
static int
doroutedrop(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
char dest[AXALEN], neighbor[AXALEN] ;
struct iface *ifp;
/* format destination and neighbor callsigns */
if(setcall(dest,argv[1]) == -1) {
tprintf("bad destination callsign\n") ;
return -1 ;
}
if(setcall(neighbor,argv[2]) == -1) {
tprintf("bad neighbor callsign\n") ;
return -1 ;
}
/* find interface */
if((ifp = if_lookup(argv[3])) == NULLIF) {
tprintf(Badinterface,argv[3]);
return 1;
}
/* Is it a netrom interface ? */
if(!(ifp->flags & IS_NR_IFACE)) {
tprintf(Badinterface,argv[3]) ;
return -1 ;
}
return nr_routedrop(dest,neighbor,ifp) ;
}
/* Broadcast nodes list on named interface. */
static int
dobcnodes(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
struct iface *ifp;
/* find interface */
if((ifp = if_lookup(argv[1])) == NULLIF) {
tprintf(Badinterface,argv[1]);
return 1;
}
/* Is it a netrom interface ? */
if(!(ifp->flags & IS_NR_IFACE)) {
tprintf(Badinterface,argv[1]) ;
return -1 ;
}
nr_bcnodes(ifp) ;
return 0;
}
/* Poll nodes for routes on named interface. - WG7J */
static int
dobcpoll(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
struct iface *ifp;
/* find interface */
if((ifp = if_lookup(argv[1])) == NULLIF) {
tprintf(Badinterface,argv[1]);
return 1;
}
/* Is it a netrom interface ? */
if(!(ifp->flags & IS_NR_IFACE)) {
tprintf(Badinterface,argv[1]) ;
return -1 ;
}
nr_bcpoll(ifp) ;
return 0;
}
/* Set outbound node broadcast interval */
static int
donodetimer(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2){
tprintf("Nodetimer %lu/%lu seconds\n",
read_timer(&Nodetimer)/1000L,
dur_timer(&Nodetimer)/1000L);
return 0;
}
stop_timer(&Nodetimer) ; /* in case it's already running */
Nodetimer.func = (void (*)())donodetick;/* what to call on timeout */
Nodetimer.arg = NULLCHAR; /* dummy value */
set_timer(&Nodetimer,atoi(argv[1])*1000L); /* set timer duration */
start_timer(&Nodetimer); /* and fire it up */
return 0;
}
void
donodetick()
{
struct iface *ifp;
for(ifp=Ifaces;ifp;ifp=ifp->next)
if(ifp->flags & IS_NR_IFACE)
nr_bcnodes(ifp) ;
/* Restart timer */
start_timer(&Nodetimer) ;
}
/* Set timer for aging routes */
static int
doobsotimer(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2){
tprintf("Obsotimer %lu/%lu seconds\n",
read_timer(&Obsotimer)/1000L,
dur_timer(&Obsotimer)/1000L);
return 0;
}
stop_timer(&Obsotimer) ; /* just in case it's already running */
Obsotimer.func = (void (*)())doobsotick;/* what to call on timeout */
Obsotimer.arg = NULLCHAR; /* dummy value */
set_timer(&Obsotimer,atoi(argv[1])*1000L); /* set timer duration */
start_timer(&Obsotimer); /* and fire it up */
return 0;
}
/* Go through the routing table, reducing the obsolescence count of
* non-permanent routes, and purging them if the count reaches 0
*/
void
doobsotick()
{
register struct nrnbr_tab *np ;
register struct nrroute_tab *rp, *rpnext ;
register struct nr_bind *bp, *bpnext ;
int i ;
for(i = 0 ; i < NRNUMCHAINS ; i++) {
for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rpnext) {
rpnext = rp->next ; /* save in case we free this route */
/* Check all bindings for this route */
for(bp = rp->routes ; bp != NULLNRBIND ; bp = bpnext) {
bpnext = bp->next ; /* in case we free this binding */
if(bp->flags & NRB_PERMANENT) /* don't age these */
continue ;
if(--bp->obsocnt == 0) { /* time's up! */
if(bp->next != NULLNRBIND)
bp->next->prev = bp->prev ;
if(bp->prev != NULLNRBIND)
bp->prev->next = bp->next ;
else
rp->routes = bp->next ;
rp->num_routes-- ; /* one less binding */
np = bp->via ; /* find the neighbor */
free((char *)bp) ; /* now we can free the bind */
/* Check to see if we can free the neighbor */
if(--np->refcnt == 0) {
if(np->next != NULLNTAB)
np->next->prev = np->prev ;
if(np->prev != NULLNTAB)
np->prev->next = np->next ;
else {
Nrnbr_tab[nrhash(np->call)] = np->next ;
}
free((char *)np) ; /* free the storage */
}
}
}
if(rp->num_routes == 0) { /* did we free them all? */
if(rp->next != NULLNRRTAB)
rp->next->prev = rp->prev ;
if(rp->prev != NULLNRRTAB)
rp->prev->next = rp->next ;
else
Nrroute_tab[i] = rp->next ;
/* No more routes left !
* We should close/reset any netrom connections
* still idling for this route ! - WG7J
*/
nrresetlinks(rp);
free((char *)rp) ;
}
}
}
start_timer(&Obsotimer) ;
}
static struct cmds Nfcmds[] = {
"add", donfadd, 0, 3,
"netrom nodefilter add <neighbor> <interface> [quality]",
"drop", donfdrop, 0, 3,
"netrom nodefilter drop <neighbor> <interface>",
"mode", donfmode, 0, 0, NULLCHAR,
NULLCHAR, NULLFP, 0, 0,
"nodefilter subcommands: add drop mode",
} ;
/* nodefilter command multiplexer */
static int
donodefilter(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
if(argc < 2) {
donfdump() ;
return 0 ;
}
return subcmd(Nfcmds,argc,argv,p) ;
}
/* display a list of <callsign,interface> pairs from the filter
* list.
*/
static int
donfdump()
{
int i, column = 1 ;
struct nrnf_tab *fp ;
char buf[AXBUF] ;
for(i = 0 ; i < NRNUMCHAINS ; i++)
for(fp = Nrnf_tab[i] ; fp != NULLNRNFTAB ; fp = fp->next) {
pax25(buf,fp->neighbor) ;
tprintf("%-7s %-8s %-3d ",
buf,fp->iface->name, fp->quality) ;
if(column++ == 3) {
if(tprintf("\n") == EOF)
return 0;
column = 1 ;
}
}
if(column != 1)
tprintf("\n") ;
return 0 ;
}
/* add an entry to the filter table */
static int
donfadd(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
struct iface *ifp;
unsigned qual;
char neighbor[AXALEN] ;
/* format callsign */
if(setcall(neighbor,argv[1]) == -1) {
tprintf("bad neighbor callsign\n") ;
return -1 ;
}
/* find interface */
if((ifp = if_lookup(argv[2])) == NULLIF) {
tprintf(Badinterface,argv[2]);
return 1;
}
/* Is it a netrom interface ? */
if(!(ifp->flags & IS_NR_IFACE)) {
tprintf(Badinterface,argv[2]) ;
return -1 ;
}
qual = ifp->quality; /* set default quality */
if(argc > 3)
qual = atoi(argv[3]);
return nr_nfadd(neighbor,ifp,qual) ;
}
/* drop an entry from the filter table */
static int
donfdrop(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
struct iface *ifp;
char neighbor[AXALEN] ;
/* format neighbor callsign */
if(setcall(neighbor,argv[1]) == -1) {
tprintf("bad neighbor callsign\n") ;
return -1 ;
}
/* find interface */
if((ifp = if_lookup(argv[2])) == NULLIF) {
tprintf(Badinterface,argv[2]);
return 1;
}
/* Is it a netrom interface ? */
if(!(ifp->flags & IS_NR_IFACE)) {
tprintf(Badinterface,argv[2]) ;
return -1 ;
}
return nr_nfdrop(neighbor,ifp) ;
}
/* nodefilter mode subcommand */
static int
donfmode(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
if(argc < 2) {
tprintf("filter mode is ") ;
switch(Nr_nfmode) {
case NRNF_NOFILTER:
tprintf("none\n") ;
break ;
case NRNF_ACCEPT:
tprintf("accept\n") ;
break ;
case NRNF_REJECT:
tprintf("reject\n") ;
break ;
default:
tprintf("some strange, unknown value\n") ;
}
return 0 ;
}
switch(argv[1][0]) {
case 'n':
case 'N':
Nr_nfmode = NRNF_NOFILTER ;
break ;
case 'a':
case 'A':
Nr_nfmode = NRNF_ACCEPT ;
break ;
case 'r':
case 'R':
Nr_nfmode = NRNF_REJECT ;
break ;
default:
tprintf("modes are: none accept reject\n") ;
return -1 ;
}
return 0 ;
}
/* netrom network packet time-to-live initializer */
static int
donrttl(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setshort(&Nr_ttl,"Time to live",argc,argv);
}
/* show hidden (ie '#...') nodes or not */
static int
donrhidden(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setbool(&Nr_hidden,"Hidden nodes",argc,argv);
}
/* allow automatic derating of netrom routes on link failure */
static int
donrderate(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
extern int Nr_derate;
return setbool(&Nr_derate,"Derate flag",argc,argv);
}
/* promiscuous acceptance of broadcasts */
static int
donrpromisc(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
extern int Nr_promisc;
return setbool(&Nr_promisc,"Promiscuous flag",argc,argv);
}
#ifdef ALLSESSIONS
/* Initiate a NET/ROM transport connection */
static int
donrconnect(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
struct nrroute_tab *np;
struct sockaddr_nr lsocket, fsocket;
char alias[AXBUF];
struct session *sp;
int split = 0;
/*Make sure this comes from console - WG7J*/
if(Curproc->input != Command->input)
return 0;
#ifdef ALLSERV
if(argv[0][0] == 's')
split = 1;
#endif
/* Get a session descriptor */
if((sp = newsession(argv[1],NRSESSION,split)) == NULLSESSION) {
tputs(TooManySessions);
return 1 ;
}
if((sp->s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
tputs(Nosock);
keywait(NULLCHAR,1);
freesession(sp);
return 1;
}
/* See if the requested destination is a known alias or call,
* use it if it is. Otherwize give an error message. - WG7J
*/
putalias(alias,argv[1],0);
strupr(argv[1]); /*make sure it's upper case*/
if((np = find_nrboth(alias,argv[1])) == NULLNRRTAB){
/*no such call or node alias*/
tputs("no such node\n\n");
keywait(NULLCHAR,1);
freesession(sp);
return 1;
}
/* Setup the local side of the connection */
lsocket.nr_family = AF_NETROM;
/* Set up our local username, bind would use Mycall instead */
memcpy(lsocket.nr_addr.user,Nr4user,AXALEN);
/* Putting anything else than Nr_iface->hwaddr here will not work ! */
memcpy(lsocket.nr_addr.node,Nr_iface->hwaddr,AXALEN);
/* Now bind the socket to this */
bind(sp->s,(char *)&lsocket,sizeof(struct sockaddr_nr));
/* Set up the remote side of the connection */
fsocket.nr_family = AF_NETROM;
memcpy(fsocket.nr_addr.user,np->call,AXALEN);
memcpy(fsocket.nr_addr.node,np->call,AXALEN);
fsocket.nr_family = AF_NETROM;
return tel_connect(sp, (char *)&fsocket, sizeof(struct sockaddr_nr));
}
#endif
/* Reset a net/rom connection abruptly */
static int
donrreset(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct nr4cb *cb ;
#ifndef TNOS_68K
cb = MK_FP(htoi(argv[1]),8);
#else
cb = htoi(argv[1]);
#endif
if(!nr4valcb(cb)){
tprintf(Notval);
return 1;
}
reset_nr4(cb);
return 0;
}
/* Force retransmission on a net/rom connection */
static int
donrkick(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct nr4cb *cb ;
#ifndef TNOS_68K
cb = MK_FP(htoi(argv[1]),8);
#else
cb = htoi(argv[1]);
#endif
if(kick_nr4(cb) == -1) {
tprintf(Notval);
return 1;
} else
return 0;
}
/* netrom transport ACK delay timer */
static int
donracktime(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setlong(&Nr4acktime,"Ack delay time (ms)",argc,argv);
}
/* netrom transport choke timeout */
static int
donrchoketime(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setlong(&Nr4choketime,"Choke timeout (ms)",argc,argv);
}
/* netrom transport initial round trip time */
static int
donrirtt(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setlong(&Nr4irtt,"Initial RTT (ms)",argc,argv);
}
/* netrom transport receive queue length limit. This is the */
/* threshhold at which we will CHOKE the sender. */
static int
donrqlimit(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setshort(&Nr4qlimit,"Queue limit (bytes)",argc,argv);
}
/* Display or change our NET/ROM username */
static int
donruser(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char buf[AXBUF];
if(argc < 2){
pax25(buf,Nr4user);
tprintf("%s\n",buf);
return 0;
}
if(setcall(Nr4user,argv[1]) == -1)
return -1;
Nr4user[ALEN] |= E;
return 0;
}
/* netrom transport maximum window. This is the largest send and */
/* receive window we may negotiate */
static int
donrwindow(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setshort(&Nr4window,"Window (frames)",argc,argv);
}
/* netrom transport maximum retries. This is used in connect and */
/* disconnect attempts; I haven't decided what to do about actual */
/* data retries yet. */
static int
donrretries(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setshort(&Nr4retries,"Retry limit",argc,argv);
}
/* Display the status of NET/ROM connections */
static int
donrstatus(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
int i ;
struct nr4cb *cb ;
char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
if(argc < 2) {
tprintf("&NCB Snd-W Snd-Q Rcv-Q LUser RUser @Node State\n");
for(i = 0 ; i < NR4MAXCIRC ; i++) {
if((cb = Nr4circuits[i].ccb) == NULLNR4CB)
continue ;
pax25(luser,cb->local.user) ;
pax25(ruser,cb->remote.user) ;
pax25(node,cb->remote.node) ;
if(tprintf("%4.4x %3d %5d %5d %9s %9s %-9s %s\n",
FP_SEG(cb), cb->nbuffered, len_q(cb->txq),
len_p(cb->rxq), luser, ruser, node,
Nr4states[cb->state]) == EOF)
break;
}
return 0 ;
}
#ifndef TNOS_68K
cb = MK_FP(htoi(argv[1]),8);
#else
cb = htoi(argv[1]);
#endif
if(!nr4valcb(cb)) {
tprintf(Notval) ;
return 1 ;
}
donrdump(cb) ;
return 0 ;
}
/* Dump one control block */
void
donrdump(cb)
struct nr4cb *cb ;
{
char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
unsigned seq ;
struct nr4txbuf *b ;
struct timer *t ;
pax25(luser,cb->local.user) ;
pax25(ruser,cb->remote.user) ;
pax25(node,cb->remote.node) ;
tprintf("Local: %s %d/%d Remote: %s @ %s %d/%d State: %s\n",
luser, cb->mynum, cb->myid, ruser, node,
cb->yournum, cb->yourid, Nr4states[cb->state]) ;
tprintf("Window: %-5u Rxpect: %-5u RxNext: %-5u RxQ: %-5d %s\n",
cb->window, uchar(cb->rxpected), uchar(cb->rxpastwin),
len_p(cb->rxq), cb->qfull ? "RxCHOKED" : "") ;
tprintf(" Unack: %-5u Txpect: %-5u TxNext: %-5u TxQ: %-5d %s\n",
cb->nbuffered, uchar(cb->ackxpected), uchar(cb->nextosend),
len_q(cb->txq), cb->choked ? "TxCHOKED" : "") ;
tprintf("TACK: ") ;
if(run_timer(&cb->tack))
tprintf("%lu", read_timer(&cb->tack)) ;
else
tprintf("stop") ;
tprintf("/%lu ms; ", dur_timer(&cb->tack)) ;
tprintf("TChoke: ") ;
if(run_timer(&cb->tchoke))
tprintf("%lu", read_timer(&cb->tchoke)) ;
else
tprintf("stop") ;
tprintf("/%lu ms; ", dur_timer(&cb->tchoke)) ;
tprintf("TCD: ") ;
if(run_timer(&cb->tcd))
tprintf("%lu", read_timer(&cb->tcd)) ;
else
#ifndef NR4TDISC
tprintf("stop") ;
tprintf("/%lu ms", dur_timer(&cb->tcd)) ;
#else
tprintf("stop") ;
tprintf("/%lu ms; ", dur_timer(&cb->tcd)) ;
tprintf("TDisc: ") ;
if(run_timer(&cb->tdisc))
tprintf("%lu", (read_timer(&cb->tdisc)/1000L)) ;
else
tprintf("stop") ;
tprintf("/%lu", (dur_timer(&cb->tdisc)/1000L)) ;
#endif
if(run_timer(&cb->tcd))
tprintf("; Tries: %u\n", cb->cdtries) ;
else
tputc('\n') ;
tprintf("Backoff Level %u SRTT %ld ms Mean dev %ld ms\n",
cb->blevel, cb->srtt, cb->mdev) ;
/* If we are connected and the send window is open, display */
/* the status of all the buffers and their timers */
if(cb->state == NR4STCON && cb->nextosend != cb->ackxpected) {
tprintf("TxBuffers: Seq Size Tries Timer\n") ;
for(seq = cb->ackxpected ;
nr4between(cb->ackxpected, seq, cb->nextosend) ;
seq = (seq + 1) & NR4SEQMASK) {
b = &cb->txbufs[seq % cb->window] ;
t = &b->tretry ;
if(tprintf(" %3u %3d %5d %lu/%lu\n",
seq, len_p(b->data), b->retries + 1,
read_timer(t), dur_timer(t))
== EOF)
break;
}
}
}
/* netrom timers type - linear v exponential */
static
donrtype(argc,argv,p)
int argc ;
char *argv[] ;
void *p ;
{
extern unsigned Nr_timertype;
if(argc < 2) {
tprintf("Netrom timer type is %s\n", Nr_timertype ? "linear" : "exponential" ) ;
return 0 ;
}
switch(argv[1][0]) {
case 'l':
case 'L':
Nr_timertype = 1 ;
break ;
case 'e':
case 'E':
Nr_timertype = 0 ;
break ;
default:
tprintf("use: netrom timertype [linear|exponential]\n") ;
return -1 ;
}
return 0 ;
}
static
dominquality(argc,argv,p)
int argc ;
char *argv[] ;
void *p ;
{
unsigned val ;
extern unsigned Nr_autofloor;
if(argc < 2) {
tprintf("%u\n", Nr_autofloor) ;
return 0 ;
}
val = atoi(argv[1]) ;
if(val == 0 || val > 255 ) {
tprintf("The minimum acceptable quality must be 1 to 255\n") ;
return 1 ;
}
Nr_autofloor = val ;
return 0 ;
}
/* Fixed and now functional, 920317 WG7J */
int
donrload(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
char buff[255];
FILE *fn;
time_t now, prev;
long t1,t2;
int quality,obso,j;
int permanent,record;
struct iface *ifp;
char alias[12],dest[12],iface[12],neighbor[12],type[3],*ptr;
char destalias[ALEN+1]; /*alias in 'alias form'*/
char destcall[AXALEN]; /*in callsign (ie shifted) form */
char destneighbor[AXALEN];
if(Nr_iface == NULLIF) {
tputs("Attach netrom interface first\n") ;
return 1;
}
if((fn = fopen(Netromfile,READ_TEXT)) == NULLFILE){
/*
tputs("Can't open netrom save file!\n");
*/
return 1;
}
if(fgets(buff,sizeof(buff),fn) == NULLCHAR){ /* read the timestamp */
fclose(fn);
return 1;
}
if((strncmp(buff,"time = ",7))!= 0){
/*
tputs("Wrong node file content\n");
*/
fclose(fn);
return 1;
}
time(&now);
sscanf(buff,"time =%ld",&prev);
/*
tprintf("now = %ld , prev = %ld\n",now,prev);
*/
if(prev >= now){
/*
tputs("You traveled back in time!!\n");
*/
fclose(fn);
return 1;
}
#ifdef notdef
t1 = now - prev;
t2 = dur_timer(&Obsotimer)/1000L;
j = t1 / t2; /* recalculate obsolete count */
tprintf("%ld seconds are past ( %d obsolete scans)\n",t1,j);
#endif
while(fgets(buff,sizeof(buff),fn) != NULLCHAR){
if((ptr = strchr(buff,':')) == 0){
sscanf(buff,"%s%s%i%i%s%s"
,dest,type,&quality,&obso,iface,neighbor);
alias[0] = '\0';
} else {
*ptr = ' ';
sscanf(buff,"%s%s%s%i%i%s%s"
,alias,dest,type,&quality,&obso,iface,neighbor);
}
/*Set and check calls / alias - WG7J */
if(setcall(destcall,dest) == -1) {
/*
tprintf("Bad call %s\n",dest);
*/
continue;
}
if(setcall(destneighbor,neighbor) == -1) {
/*
tprintf("Bad call %s\n",neighbor);
*/
continue;
}
if(putalias(destalias,alias,1) == -1)
continue;
/* find interface */
if((ifp = if_lookup(iface)) == NULLIF)
continue;
/* Is it a netrom interface ? */
if(!(ifp->flags & IS_NR_IFACE))
continue;
/* get and check quality value */
if(quality > 255 || quality < Nr_autofloor) {
/*
tprintf("maximum route quality is 255\n") ;
*/
continue;
}
/* Check the type of route - WG7J */
permanent = record = 0;
if(strchr(type,'P') != NULLCHAR)
permanent = 1;
else {
if(strchr(type,'R') != NULLCHAR)
record = 1;
}
nr_routeadd(destalias,destcall,ifp,quality,destneighbor, \
permanent,record) ;
}
fclose(fn);
return 0;
}
int
donrsave(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
register struct nrroute_tab *rp ;
register struct nr_bind *bp ;
register struct nrnbr_tab *np ;
char dest[AXALEN] ;
char neighbor[AXBUF] ;
register int i;
char buf[16] ;
char *cp ;
FILE *fn;
time_t now;
#ifdef __TURBOC__
if((fn = fopen(Netromfile,"wt+")) == NULLFILE){
#else
if((fn = fopen(Netromfile,"w+")) == NULLFILE){
#endif
tputs("Can't write netrom save file!\n");
return 1;
}
time(&now);
fprintf(fn,"time = %ld\n",now);
for(i = 0 ; i < NRNUMCHAINS ; i++){
for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next){
strcpy(buf,rp->alias) ;
/* remove trailing spaces */
if((cp = strchr(buf,' ')) == NULLCHAR)
cp = &buf[strlen(buf)] ;
if(cp != buf) /* don't include colon for null alias */
*cp++ = ':' ;
for(bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
pax25(cp,rp->call) ;
fprintf(fn,"%-16s ",buf) ;
np = bp->via ;
if(fprintf(fn,"%1s %3d %3d %-8s %s\n",
(bp->flags & NRB_PERMANENT ? "P" :
bp->flags & NRB_RECORDED ? "R" : "X"),
bp->quality,bp->obsocnt,
np->iface->name,
pax25(neighbor,np->call)) == EOF)
break;
}
}
}
fclose(fn);
return 0;
}